<?php
/**
  *   2016年7月6日16:01:17
  *   XML解析函数
**/
namespace hyang;
use DOMDocument;
use Exception;
class Xml{
    public $fname;//xml文件路径
    public $error;//错误信息
    public $dom;//XML库
    public $selectLink;// 选择器链式操作
    public function __construct($opt=null)
    {
        $this->init($opt);       
    }
    //项目初始化
    public function init($opt=null)
    {
        if($opt){
             if(isset($opt['xml']) || is_file($opt)){
                $file = isset($opt['xml'])? $opt['xml']:$opt;
                if(substr_count(strtolower($file),'.xml') <1) $file .= '.xml';
                if(is_file($file)){
                    $this->dom = new DOMDocument();
                    $this->dom->load($file);
                    $this->fname = $file;
                }else{
                    $thsi->record('<br>>>'.$fname.'文件不存在',true);
                }                
            }
        }else{
            $this->error = date('Y-m-d H:i:s').'>>系统初始化失败';
        }
    }
    //通过标签名称获取元素
    //$getAll 获取全部
    public function tags($name,$getOne=null)
    {
        $dom = $this->dom;
		if(!is_object($dom)) return '';
		$elemt = $dom->getElementsByTagName($name);
        $getAll = $getOne? null:true;
		$data = $this->_parseXML($elemt,$getAll);
		return $data;
    }
    //标签解析
    private function _parseXML($doc,$getAll=null)
	{
		if(!is_object($doc)){
			$this->errorInfo('#eafx->_parseXML: $doc无效！！~不是对象。');
			return '';
		}
		$data = array();
		if($getAll) $dataAll = array();
		try{
			$childNodes = property_exists($doc,'childNodes')? $doc->childNodes : $doc;
			if(!is_object($childNodes)){
				$this->errorInfo('#eafx->_parseXML: $doc->childNodes无效！！');
				return '';
			} 
			foreach ($childNodes  as $item) {
				$key = $item->nodeName;
				$attrK2V = array();
				$data[$key] = $this->_parseXML($item);
				foreach($item->attributes as $attr)
				{
					$kk = $attr->name;
					$vv = $attr->value;
					$attrK2V[$kk] = $vv;
				}
				if(count($attrK2V)>0){
					if(!is_array($data[$key])) $data[$key] = array();
					$data[$key] = array_merge(array('K2V'=>$attrK2V),$data[$key]);
				} 
				if($getAll) $dataAll[] = $data;
			}
			if($getAll) $data = $dataAll;
		}catch(Exception $e){
			return '';
		}
		if(count($data)<1) return '';
		return $data;
	}
    /**
		通过 属性值获取元素  
		$nodeName 在给定的节点下获取属性的值
		$setAttrVal 设置查询到的值
        $attrName: array/string
	**/
	public function attr($attrName,$nodeName=null,$setAttrVal=null)
	{
		$dom = $this->dom;
		if(!is_object($dom)){
			$this->record('#eafx->attr: 没有获取到$dom！！');
			return '';
		}
		$data = array();
		if($nodeName){
			$nodes = $dom->getElementsByTagName($nodeName);
			foreach ($nodes as $itemNode) {
				if($setAttrVal) $itemNode->setAttribute($attrName,$setAttrVal);
				else{
                    if(is_array($attrName)){//获取多属性
                        $tmp = [];
                        foreach($attrName as $v){
                            $tmp[$v] = $itemNode->getAttribute($v);
                        }
                        $data[] = $tmp;
                    }else $data[] = $itemNode->getAttribute($attrName);
                } 
			}
			if($setAttrVal && $this->fname){
				$dom->save($this->fname);
				return true;
			} 
			else return $data;
		}else{

		}
	}
    /**
        解析XML节点信息，包括子信息/当前节点所有信息
        2016年7月6日
        $node 节点名称
        $nolist 不是列表，表示子项之间的标签名互不相同，相同的话会出项多重数级
        出现debug#重复的子标签无法判别,目前无法解决
    **/
    public function node($node,$nolist=false)
    {
        $dom = $this->dom;
		if(!is_object($dom)){
			$this->record('#eafx->node: 没有获取到$dom！！');
			return '';            
		}
        $data = [];
        $n = $dom->getElementsByTagName($node);
        foreach($n as $nlist){
            $tmp = [];
            foreach($nlist->attributes as $alist){
                $tmp[$alist->name] = $alist->value;
            }
            if(count($tmp)>0) $data['attr'] = $tmp;
            $tmp = [];
            foreach($nlist->childNodes as $clist){
                //debug($clist);
                $tag = $clist->tagName;
                $chd = $this->node($tag,$nolist);
                if($tag){
                    if($nolist) $tmp[$tag] = empty($chd)? '':$chd;
                    else $tmp[][$tag] = empty($chd)? '':$chd;
                }
            }
            if(count($tmp)>0) $data['children'] = $tmp;
        }
        //debug($data);
        return $data;
    }
    //写入记录
    public function record($str,$append=false)
    {
        if($append){
            $str = ($this->error).$str;
        }
        $this->error = $str;
    }
    //错误信息
    public function error($opt=null)
    {
        $str = $this->error;
        if($opt) return $str;
        if($str) echo '<br>'.$str.'<br>';
    }
    /********************************************* 2016年11月8日 星期二  Begin************************************************************************************************/
    public function select($seleter)
    {
        $this->selectLink = null;
		if(!is_object($this->dom)){
			$this->record('#eafx->node: 没有获取到$dom！！');
			return '';            
		}
        if(substr_count($seleter,'#')>0)  $this->selectLink = $this->dom->getElementById(str_replace('#','',$seleter));
        else  $this->selectLink = $this->dom->getElementsByTagName($seleter);
        return $this;
        //debug($this->dom,'type');
        //debug($this->dom->getElementsByTagName('test'),'type');
        //debug($elmt,'type');
        //childNodes
    }
    public function hasElement($seleter)
    {
        if(substr_count($seleter,'#')>0){
            $elmt = $this->dom->getElementById(str_replace('#','',$seleter));
            if($elemt) return true;
            return false;
        }
        else $elmt = $this->dom->getElementsByTagName($seleter);
        if($elmt->length > 0) return true;
        return false;
    }
    // 多个相同元素获取第一个元素
    public function first()
    {
        $elmt = $this->selectLink;
        if($elmt){
            foreach($elmt as $n){            
                $node = (new Node())->_setAttr($n->attributes);
                $this->selectLink = null;
                return $node;
            }
        }        
    }
    // 获取元素的文本内容
    public function text()
    {
        $elmt = $this->selectLink;
        if($elmt){
            foreach($elmt as $n){
                return $n->nodeValue;
            }
        }
        return '';
    }
    // 子节点
    public function children()
    {
        return (new Node())->_setElement($this->selectLink);
    }
}
class Node
{
    public $attrLink;
    public $elemLink;
    public function _setAttr($dom)
    {
        $this->attrLink = $dom;
        return $this;
    }
    // 获取属性
    public function attr($key=null)
    {
        if(is_object($key)){
            $at = $key;
            $key = null;
        }
        else $at = $this->attrLink;
        $data = [];
        if($at){
            foreach($at as $n){
                if($key){
                    if($key == $n->nodeName) return $n->nodeValue;
                }
                else $data[$n->nodeName] = $n->nodeValue;
            }
        }
        $this->attrLink = null;
        if($key) return '';
        return $data;
    }
    // 节点
    public function _setElement($dom)
    {
        $this->elemLink = $dom;
        return $this;
    }
    // 文件列表
    public function nameList()
    {
        $dom = $this->elemLink;
        $name = [];
        foreach($dom as $n){
            //debug($n,'type');return;
            //debug($n->childNodes,'type');return;
            foreach($n->childNodes as $cn){
                if(get_class($cn) == "DOMText") continue;
                $name[] = $cn->tagName;
            }
        }
        //debug($name,'type-');return;
        return $name;
    }
    // 获取属性以及名称
    public function childAttr()
    {
        $dom = $this->elemLink;
        $ret = [];
        $key = '';
        foreach($dom as $n){
            foreach($n->childNodes as $cn){
                if(get_class($cn) == "DOMText") continue;
                $key = $cn->tagName;
                $ret[$key] = $this->attr($cn->attributes); 
                //debug($cn,'type');return;
            }
        }
        return $ret;
    }
    // 获取文本内容以及名称
    public function childText()
    {
        $dom = $this->elemLink;
        $ret = [];
        $key = '';
        foreach($dom as $n){
            foreach($n->childNodes as $cn){
                if(get_class($cn) == "DOMText") continue;
                $key = $cn->tagName;
                $ret[$key] = $cn->nodeValue; 
                //debug($cn,'type');return;
            }
        }
        return $ret;
    }
}
/********************************************* 2016年11月8日 星期二  End************************************************************************************************/
